package org.jeecg.modules.third.digitalseal.utils;

import cn.hutool.core.codec.Base64Decoder;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.apache.pdfbox.util.Matrix;
import org.jeecg.common.util.DateUtils;
import org.jeecg.modules.wlhy.company.entity.HyCompany;
import org.jeecg.modules.wlhy.customer.entity.HyCustomerCompany;
import org.jeecg.modules.wlhy.hydriver.entity.HyDriver;
import org.jeecg.modules.wlhy.order.entity.HyOrder;
import org.junit.Test;
import org.springframework.util.Base64Utils;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.List;

/**
 * @Description: PDF编辑工具
 * @author: luruirui
 * @date: 2021年04月19日 13:43
 */
public class PdfEditUtil {
    private static String FONT_PATH = "font/simsun.ttf";//宋体
    private static PDFont FONT = PDType1Font.HELVETICA;
    private static float FONT_SIZE = 14;//四号
    private static final float LEADING = -1.5f * FONT_SIZE;

    private static float WIDTH = 150;//添加图片宽度
    private static float HEIGHT = 150;//添加图片高度

    //文件保存地址路径
    private static String SAVE_CONTRACT_ADDR = "documents" + File.separator  +  DateUtils.getDate("yyyyMMdd")+ File.separator;

    //创建PDPageContentStream
    public static PDPageContentStream getPDPageContentStream(PDDocument document, int pageIndex) throws IOException {
          // Retrieving the pages of the document, and using PREPEND mode
        PDPage page = document.getPage(pageIndex);
        PDPageContentStream contentStream = new PDPageContentStream(document, page,
                PDPageContentStream.AppendMode.PREPEND, false);

        InputStream inFont = PdfEditUtil.class.getClassLoader().getResourceAsStream(FONT_PATH);
        PDType0Font font = PDType0Font.load(document, inFont);
        //PDType0Font font = PDType0Font.load(document, new File("C:\\opt\\upFiles\\simsun.ttf"));

        // Setting the font to the Content stream
        contentStream.setFont(font, FONT_SIZE);//四号

        return contentStream;
    }
    //PDF添加文本
    public static void showTextByLeft(PDPageContentStream contentStream, String txt, String def, float x, float y) throws Exception{
        //Begin the Content stream
        contentStream.beginText();

        if (null == txt) {
            txt = def;
        }

        //Setting the position for the line
        contentStream.newLineAtOffset(x, y);

        //Adding text in the form of string
        contentStream.showText(txt);

        //Ending the content stream
        contentStream.endText();
    }
    //PDF添加图片
    public static boolean addImage(PDPageContentStream contentStream, PDDocument document, String imagePath, float x, float y) throws IOException{
        File picture = new File(imagePath);
//        BufferedImage sourceImg = ImageIO.read(new FileInputStream(picture));
        BufferedImage sourceImg = ImageIO.read(picture);
        if(sourceImg == null) {
            System.out.println("addImage PDF添加图片时读取图片失败");
            return false;
        }
        float imgWidth = sourceImg.getWidth();
        float imgHeight = sourceImg.getHeight();
//        System.out.println("原图大小: " + imgWidth + " * " + imgHeight);
        //图片缩放倍数
        float scaleHeight = WIDTH / imgWidth * imgHeight;
//        System.out.println("缩放后大小: " + WIDTH + " * " + scaleHeight);
        //添加图片
        // Loading img from file
        PDImageXObject pdImage = PDImageXObject.createFromFile(imagePath, document);
        if(pdImage == null) {
            System.out.println("addImage PDF添加图片时img转PDFImage失败");
            return false;
        }
        // Draw image by  x y width height
        contentStream.drawImage(pdImage, x, y, WIDTH, scaleHeight);
        return true;
    }
    //PDF添加水印------
    public static void addWaterMark(PDDocument document,String ts) throws IOException{
        // Adding watermark
        for(PDPage everyPage:document.getPages()){
            PDPageContentStream cs = new PDPageContentStream(document, everyPage, PDPageContentStream.AppendMode.APPEND,
                    true, true);
//            String ts = "河北一六八网络科技";
            String watermark = ts;

            float fontSize = 40.0f;

            InputStream inFont = PdfEditUtil.class.getClassLoader().getResourceAsStream(FONT_PATH);
            PDType0Font font = PDType0Font.load(document, inFont);
            //PDType0Font font = PDType0Font.load(document, new File(FONT_PATH));
            PDExtendedGraphicsState r0 = new PDExtendedGraphicsState();
            // 透明度
            r0.setNonStrokingAlphaConstant(0.3f);
            r0.setAlphaSourceFlag(true);

            cs.setGraphicsStateParameters(r0);
            cs.setNonStrokingColor(new Color(188, 188, 188));
            cs.beginText();
            cs.setFont(font, fontSize);
            // 获取旋转实例
            cs.setTextMatrix(Matrix.getRotateInstance(45,120f,90f));
            //展示水印
            cs.showText(watermark);
            cs.endText();

            cs.close();
        }
    }

    /**
     * 增加一段文本
     * @param contentStream
     * @param width
     * @param sx
     * @param sy
     * @param text
     * @param justify
     * @throws IOException
     */
    private static void addParagraph(PDPageContentStream contentStream, float width, float sx,
                                     float sy, String text, boolean justify) throws IOException {
        List<String> lines = new ArrayList<>();
        parseLinesRecursive(text, width, lines);

        contentStream.setFont(FONT, FONT_SIZE);
        contentStream.newLineAtOffset(sx, sy);
        for (String line: lines) {
            float charSpacing = 0;
            if (justify){
                if (line.length() > 1) {
                    float size = FONT_SIZE * FONT.getStringWidth(line) / 1000;
                    float free = width - size;
                    if (free > 0 && !lines.get(lines.size() - 1).equals(line)) {
                        charSpacing = free / (line.length() - 1);
                    }
                }
            }
            contentStream.setCharacterSpacing(charSpacing);
            contentStream.showText(line);
            contentStream.newLineAtOffset(0, LEADING);
        }
    }

    /**
     * 递归分析文本，并按宽度分割成N行
     * @param text
     * @param width
     * @param lines
     * @return
     * @throws IOException
     */
    private static List<String> parseLinesRecursive(String text, float width, List<String> lines) throws IOException {
        String tmpText = text;
        for (int i=0; i<text.length(); i++) {
            tmpText = text.substring(0, text.length() - i);

            float realWidth = FONT_SIZE * FONT.getStringWidth(tmpText) / 1000;

            if (realWidth > width) {
                continue;
            } else {
                lines.add(tmpText);

                if (0 != i) {
                    parseLinesRecursive(text.substring(text.length() - i), width, lines);
                }

                break;
            }
        }

        return lines;
    }

    //使用Graphics2D，计算文本宽度
    private static int calCharactersWidth(Graphics2D g, Font font, String text) {
        FontRenderContext context = g.getFontRenderContext();
        // 获取字体的像素范围对象
        Rectangle2D stringBounds = font.getStringBounds(text, context);
        int fontWidth = (int)stringBounds.getWidth();
        return fontWidth;
    }

    /**
     * 司机签定代开增值税专用发票协议
     * @param hyDriver
     * @param fileAddress 代开增值税专用发票协议
     * @param savePath
     */
    public static String addInvoiceAgreement (HyDriver hyDriver, String fileAddress, String savePath){
        try {

            File file = new File(fileAddress);
            PDDocument document = PDDocument.load(file);
            //第1页添加内容
            PDPageContentStream pageContentStream1 = getPDPageContentStream(document, 0);
            //x 左右 y 上下
            int x = 0;
            //添加姓名
            showTextByLeft(pageContentStream1, hyDriver.getDriverName(), "", 175,705);
            //添加身份证号
            showTextByLeft(pageContentStream1, hyDriver.getIdcard(), "", 200,684 + x);

            String createTime =  DateUtils.date2Str(hyDriver.getCreateTime(), DateUtils.date_sdf.get());
            String[] createTimeArray = createTime.split("-");

            //添加签订起始日期
            showTextByLeft(pageContentStream1, createTimeArray[0], "", 186,238);
            showTextByLeft(pageContentStream1, createTimeArray[1], "", 226,238);
            showTextByLeft(pageContentStream1, createTimeArray[2], "", 251,238);
            //添加签订终止日期
            int year =  Integer.parseInt(createTimeArray[0])+2;
            showTextByLeft(pageContentStream1, String.valueOf(year), "", 295,238);
            showTextByLeft(pageContentStream1,  createTimeArray[1], "", 327,238);
            showTextByLeft(pageContentStream1,  createTimeArray[2], "", 349,238);
            //签名
            showTextByLeft(pageContentStream1, hyDriver.getDriverName()+" ", "", 132,192 + x);
            // Closing the content stream
            pageContentStream1.close();
            // Saving the document
            String path = SAVE_CONTRACT_ADDR;
            String filename = "invoiceagreement_"+hyDriver.getId() ;
            String pdfPath = savePath + path + filename+".pdf";

            File pdfFile = new File(savePath + path );
            if (!pdfFile.exists()) {
                pdfFile.mkdirs();// 创建文件根目录
            }
            document.save( pdfPath );
            // Closing the document
            document.close();
            return path+filename+".pdf";
        } catch (Exception e) {
            // TODO Auto-generated catch block
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        return StringUtils.EMPTY;
    }


    //转base64
    public static String fileToBase64(String imgFilePath) {
        File file = new File(imgFilePath);
        if(!file.exists()){
            System.out.println("文件不存在 fileToBase64 : {} "+imgFilePath);
            return "";
        }

        String[] res = imgFilePath.split("\\.");
        String pos = res[res.length - 1];
        byte[] data = null;
        // 读取图片字节数组
        try {
            InputStream in = new FileInputStream(imgFilePath);
            data = new byte[in.available()];
            in.read(data);
            in.close();
        } catch (IOException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        String data1 = Base64Utils.encodeToString(data);
//        System.out.println(data1);
        return data1;
    }
    //转pdf
    public static void base64ToFile(String s ,String path){
        byte[] decode = Base64Decoder.decode(s);
        File file = new File(path);
        try {
            FileOutputStream fop =  new FileOutputStream(file);
            try {
                fop.write(decode);
                fop.flush();
                fop.close();
            } catch (IOException e) {
                System.out.println(e.getMessage());
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }

    }





    private static void testShipping(){
        try {
            // Loading an existing document
            //InputStream in = PdfEditUtil.class.getClassLoader().getResourceAsStream("VAT_INVOICE.pdf");
            //PDDocument document = PDDocument.load(in);
            File file = new File("D:\\Administrator\\桌面\\资料\\运输协议-模板添加5.5的版本.pdf");
            PDDocument document = PDDocument.load(file);
            //添加水印
            String watermark = "test";
            addWaterMark(document,watermark);

            //第1页添加内容
            PDPageContentStream pageContentStream1 = getPDPageContentStream(document, 0);
            int x = 0;
            showTextByLeft(pageContentStream1, "一六八网络科技有限公司", "", 150,675 + x);
            //添加货物名称
            showTextByLeft(pageContentStream1, "乙方", "", 150,635 + x);


            // Closing the content stream
            pageContentStream1.close();


            //第4页添加内容
            PDPageContentStream pageContentStream = getPDPageContentStream(document, 3);

            showTextByLeft(pageContentStream, "HY202106291542134723", "", 200,200 + x);
            //添加货物名称
            showTextByLeft(pageContentStream, "剪切料", "", 200,170 + x);
            //添加货物总重量
            showTextByLeft(pageContentStream, "40.00吨", "", 415,170 + x);
            //添加运费计算方式
            showTextByLeft(pageContentStream, "按单价", "", 200,140 + x);
            //添加运费单价
            showTextByLeft(pageContentStream, "850.00元/吨", "", 415,140 + x);
            //添加亏损货物单价
            showTextByLeft(pageContentStream, "3540.00元/吨", "", 200,110 + x);
            //添加亏损免赔设置
            showTextByLeft(pageContentStream, "按吨数0.200", "", 415,110 + x);
            //添加亏损免赔设置
            showTextByLeft(pageContentStream, "2021年4月19日", "", 200,75 + x);

            // Closing the content stream
            pageContentStream.close();

            //第1页添加内容
            PDPageContentStream pageContentStream2 = getPDPageContentStream(document, 4);

            //添加甲方单位公章
            addImage(pageContentStream2, document, "D:\\Administrator\\桌面\\123.jpg", 130, 690);
            //添加乙方单位公章
            addImage(pageContentStream2, document, "D:\\Administrator\\桌面\\123.jpg", 382, 690);
            //添加甲方签订日期
            showTextByLeft(pageContentStream2, "2021年4月19日", "", 155,720);
            //添加乙方签订日期
            showTextByLeft(pageContentStream2, "2021年4月19日", "", 408,720);


            // Closing the content stream
            pageContentStream2.close();


            // Saving the document
            document.save(new File("D:\\Administrator\\桌面\\123" + ".pdf"));
            // Closing the document
            document.close();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    private static void testVehicleHang(){
        try {
            // Loading an existing document
            File file = new File("F:\\opt\\upFiles\\documents\\20211122\\车辆挂靠声明_20211122170318.pdf");
            PDDocument document = PDDocument.load(file);
            //添加水印
            String watermark = "test";
            addWaterMark(document,watermark);
            //第一页
            PDPageContentStream contentStream = getPDPageContentStream(document, 0);
            //添加司机姓名
            showTextByLeft(contentStream, "路蕊蕊", "", 185,675);
            //添加司机身份证号
            showTextByLeft(contentStream, "13052719960924242X", "", 340,675);

            //办税人员
            showTextByLeft(contentStream, "河北一六八网络科技有限公司办税人员", "", 140,640);

            //添加日期
            showTextByLeft(contentStream, "2021年4月19日", "", 300,322);

            //添加司机签名
            addImage(contentStream, document, "F:\\opt\\upFiles\\wlhy\\20211122\\1637571840755_1637571840764.png", 330, 310);

            System.out.println("Content added");

            // Closing the content stream
            contentStream.close();

            // Saving the document
            document.save(new File("F:\\opt\\upFiles\\documents\\" + "车辆挂靠声明-" + DateUtils.getDate("yyyyMMddHHmmss") + ".pdf"));
            // Closing the document
            document.close();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 从网络Url中下载文件
     * @param urlStr
     * @param fileName
     * @param savePath
     * @throws IOException
     */
    public static String  downLoadByUrl(String urlStr,String savePath ,String fileName) {
        if(StringUtils.isBlank(urlStr)){
            return StringUtils.EMPTY;
        }
        try {

            URL url = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection)url.openConnection();

            if(StringUtils.isBlank(fileName)){
                fileName =   FilenameUtils.getName(url.getPath());
            }
            //设置超时间为3秒
            conn.setConnectTimeout(5*1000);
            //防止屏蔽程序抓取而返回403错误
            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
            //得到输入流
            InputStream inputStream = conn.getInputStream();
            //获取自己数组
            byte[] getData = readInputStream(inputStream);
            //文件保存位置
            File saveDir = new File(savePath);
            if(!saveDir.exists()){
                saveDir.mkdirs();
            }
//            System.out.println(saveDir+File.separator+fileName);
            File file = new File(saveDir+File.separator+fileName);
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(getData);
            if(fos!=null){
                fos.close();
            }
            if(inputStream!=null){
                inputStream.close();
            }
//            System.out.println("info:"+url+" download success");
            return saveDir+File.separator+fileName;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return StringUtils.EMPTY;
    }


    /**
     * 从输入流中获取字节数组
     * @param inputStream
     * @return
     * @throws IOException
     */
    private static  byte[] readInputStream(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while((len = inputStream.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        bos.close();
        return bos.toByteArray();
    }


}
